using Microsoft.EntityFrameworkCore;
using SheLife.Domain.Entities;
using SheLife.Infrastructure.Data;

namespace SheLife.Infrastructure.Repositories
{
    /// <summary>
    /// 帖子仓储实现
    /// </summary>
    public class PostRepository : Repository<Post>, IPostRepository
    {
        public PostRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<Post>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(p => p.UserId == userId).OrderByDescending(p => p.CreatedAt).ToListAsync();
        }

        public async Task<IEnumerable<Post>> GetByCommunityIdAsync(Guid communityId)
        {
            return await _dbSet.Where(p => p.CommunityId == communityId).OrderByDescending(p => p.CreatedAt).ToListAsync();
        }

        public async Task<IEnumerable<Post>> GetByUserIdAndCommunityIdAsync(Guid userId, Guid communityId)
        {
            return await _dbSet.Where(p => p.UserId == userId && p.CommunityId == communityId).OrderByDescending(p => p.CreatedAt).ToListAsync();
        }

        public async Task<IEnumerable<Post>> GetByTagAsync(string tag)
        {
            return await _dbSet.Where(p => p.Tags.Contains(tag)).OrderByDescending(p => p.CreatedAt).ToListAsync();
        }

        public async Task<IEnumerable<Post>> GetHotPostsAsync(int count = 10)
        {
            return await _dbSet
                .Where(p => p.Status == "published")
                .OrderByDescending(p => p.ViewCount + p.LikeCount * 2 + p.CommentCount * 3)
                .Take(count)
                .ToListAsync();
        }

        public async Task<IEnumerable<Post>> GetLatestPostsAsync(int count = 10)
        {
            return await _dbSet
                .Where(p => p.Status == "published")
                .OrderByDescending(p => p.CreatedAt)
                .Take(count)
                .ToListAsync();
        }

        public async Task<IEnumerable<Post>> GetByLifeStageAsync(string lifeStage)
        {
            return await _dbSet
                .Where(p => p.LifeStage == lifeStage || p.LifeStage == "all")
                .Where(p => p.Status == "published")
                .OrderByDescending(p => p.CreatedAt)
                .ToListAsync();
        }

        public async Task<Dictionary<string, int>> GetPostStatisticsByCommunityAsync(IEnumerable<Guid> communityIds)
        {
            var posts = await _dbSet
                .Where(p => communityIds.Contains(p.CommunityId))
                .GroupBy(p => p.CommunityId)
                .Select(p => new { CommunityId = p.Key, Count = p.Count() })
                .ToListAsync();

            return posts.ToDictionary(p => p.CommunityId.ToString(), p => p.Count);
        }

        public async Task<Dictionary<string, int>> GetPostStatisticsByUserAsync(IEnumerable<Guid> userIds)
        {
            var posts = await _dbSet
                .Where(p => userIds.Contains(p.UserId))
                .GroupBy(p => p.UserId)
                .Select(p => new { UserId = p.Key, Count = p.Count() })
                .ToListAsync();

            return posts.ToDictionary(p => p.UserId.ToString(), p => p.Count);
        }

        public async Task IncrementViewCountAsync(Guid postId)
        {
            var post = await _dbSet.FindAsync(postId);
            if (post != null)
            {
                post.ViewCount++;
                await _context.SaveChangesAsync();
            }
        }
    }

    /// <summary>
    /// 帖子评论仓储实现
    /// </summary>
    public class PostCommentRepository : Repository<PostComment>, IPostCommentRepository
    {
        public PostCommentRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<PostComment>> GetByPostIdAsync(Guid postId)
        {
            return await _dbSet
                .Where(c => c.PostId == postId)
                .OrderBy(c => c.CreatedAt)
                .ToListAsync();
        }

        public async Task<IEnumerable<PostComment>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(c => c.UserId == userId).OrderByDescending(c => c.CreatedAt).ToListAsync();
        }

        public async Task<IEnumerable<PostComment>> GetByParentCommentIdAsync(Guid parentCommentId)
        {
            return await _dbSet
                .Where(c => c.ParentCommentId == parentCommentId)
                .OrderBy(c => c.CreatedAt)
                .ToListAsync();
        }

        public async Task<Dictionary<Guid, int>> GetCommentCountByPostsAsync(IEnumerable<Guid> postIds)
        {
            var comments = await _dbSet
                .Where(c => postIds.Contains(c.PostId))
                .GroupBy(c => c.PostId)
                .Select(c => new { PostId = c.Key, Count = c.Count() })
                .ToListAsync();

            return comments.ToDictionary(c => c.PostId, c => c.Count);
        }

        public async Task<Dictionary<Guid, int>> GetReplyCountByCommentsAsync(IEnumerable<Guid> commentIds)
        {
            var replies = await _dbSet
                .Where(c => commentIds.Contains(c.ParentCommentId.Value))
                .GroupBy(c => c.ParentCommentId.Value)
                .Select(c => new { CommentId = c.Key, Count = c.Count() })
                .ToListAsync();

            return replies.ToDictionary(r => r.CommentId, r => r.Count);
        }
    }

    /// <summary>
    /// 帖子点赞仓储实现
    /// </summary>
    public class PostLikeRepository : Repository<PostLike>, IPostLikeRepository
    {
        public PostLikeRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<PostLike>> GetByPostIdAsync(Guid postId)
        {
            return await _dbSet.Where(l => l.PostId == postId).ToListAsync();
        }

        public async Task<IEnumerable<PostLike>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(l => l.UserId == userId).OrderByDescending(l => l.CreatedAt).ToListAsync();
        }

        public async Task<bool> IsUserLikedPostAsync(Guid userId, Guid postId)
        {
            return await _dbSet.AnyAsync(l => l.UserId == userId && l.PostId == postId);
        }

        public async Task<Dictionary<Guid, int>> GetLikeCountByPostsAsync(IEnumerable<Guid> postIds)
        {
            var likes = await _dbSet
                .Where(l => postIds.Contains(l.PostId))
                .GroupBy(l => l.PostId)
                .Select(l => new { PostId = l.Key, Count = l.Count() })
                .ToListAsync();

            return likes.ToDictionary(l => l.PostId, l => l.Count);
        }

        public async Task<Dictionary<Guid, int>> GetLikeCountByUsersAsync(IEnumerable<Guid> userIds)
        {
            var likes = await _dbSet
                .Where(l => userIds.Contains(l.UserId))
                .GroupBy(l => l.UserId)
                .Select(l => new { UserId = l.Key, Count = l.Count() })
                .ToListAsync();

            return likes.ToDictionary(l => l.UserId, l => l.Count);
        }
    }

    /// <summary>
    /// 社区仓储实现
    /// </summary>
    public class CommunityRepository : Repository<Community>, ICommunityRepository
    {
        public CommunityRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<Community>> GetByUserIdAsync(Guid userId)
        {
            var communityIds = await _context.Set<UserCommunity>()
                .Where(uc => uc.UserId == userId)
                .Select(uc => uc.CommunityId)
                .ToListAsync();

            return await _dbSet.Where(c => communityIds.Contains(c.Id)).OrderByDescending(c => c.MemberCount).ToListAsync();
        }

        public async Task<IEnumerable<Community>> GetByCategoryAsync(string category)
        {
            return await _dbSet.Where(c => c.Category == category).OrderByDescending(c => c.MemberCount).ToListAsync();
        }

        public async Task<IEnumerable<Community>> GetByLifeStageAsync(string lifeStage)
        {
            return await _dbSet.Where(c => c.LifeStage == lifeStage || c.LifeStage == "all").OrderByDescending(c => c.MemberCount).ToListAsync();
        }

        public async Task<IEnumerable<Community>> GetPopularCommunitiesAsync(int count = 10)
        {
            return await _dbSet
                .OrderByDescending(c => c.MemberCount)
                .Take(count)
                .ToListAsync();
        }

        public async Task<IEnumerable<Community>> GetNewestCommunitiesAsync(int count = 10)
        {
            return await _dbSet
                .OrderByDescending(c => c.CreatedAt)
                .Take(count)
                .ToListAsync();
        }

        public async Task<Dictionary<string, int>> GetCommunityStatisticsByCategoryAsync()
        {
            var communities = await _dbSet
                .GroupBy(c => c.Category)
                .Select(c => new { Category = c.Key, Count = c.Count() })
                .ToListAsync();

            return communities.ToDictionary(c => c.Category, c => c.Count);
        }

        public async Task<Dictionary<string, int>> GetCommunityStatisticsByLifeStageAsync()
        {
            var communities = await _dbSet
                .GroupBy(c => c.LifeStage)
                .Select(c => new { LifeStage = c.Key, Count = c.Count() })
                .ToListAsync();

            return communities.ToDictionary(c => c.LifeStage, c => c.Count);
        }

        public async Task IncrementMemberCountAsync(Guid communityId)
        {
            var community = await _dbSet.FindAsync(communityId);
            if (community != null)
            {
                community.MemberCount++;
                await _context.SaveChangesAsync();
            }
        }

        public async Task DecrementMemberCountAsync(Guid communityId)
        {
            var community = await _dbSet.FindAsync(communityId);
            if (community != null && community.MemberCount > 0)
            {
                community.MemberCount--;
                await _context.SaveChangesAsync();
            }
        }
    }

    /// <summary>
    /// 用户社区仓储实现
    /// </summary>
    public class UserCommunityRepository : Repository<UserCommunity>, IUserCommunityRepository
    {
        public UserCommunityRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserCommunity>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(uc => uc.UserId == userId).OrderByDescending(uc => c.JoinedAt).ToListAsync();
        }

        public async Task<IEnumerable<UserCommunity>> GetByCommunityIdAsync(Guid communityId)
        {
            return await _dbSet.Where(uc => uc.CommunityId == communityId).OrderBy(uc => uc.JoinedAt).ToListAsync();
        }

        public async Task<UserCommunity?> GetByUserIdAndCommunityIdAsync(Guid userId, Guid communityId)
        {
            return await _dbSet.FirstOrDefaultAsync(uc => uc.UserId == userId && uc.CommunityId == communityId);
        }

        public async Task<bool> IsUserInCommunityAsync(Guid userId, Guid communityId)
        {
            return await _dbSet.AnyAsync(uc => uc.UserId == userId && uc.CommunityId == communityId);
        }

        public async Task<Dictionary<Guid, int>> GetUserCountByCommunitiesAsync(IEnumerable<Guid> communityIds)
        {
            var userCommunities = await _dbSet
                .Where(uc => communityIds.Contains(uc.CommunityId))
                .GroupBy(uc => uc.CommunityId)
                .Select(uc => new { CommunityId = uc.Key, Count = uc.Count() })
                .ToListAsync();

            return userCommunities.ToDictionary(uc => uc.CommunityId, uc => uc.Count);
        }

        public async Task<Dictionary<Guid, int>> GetCommunityCountByUsersAsync(IEnumerable<Guid> userIds)
        {
            var userCommunities = await _dbSet
                .Where(uc => userIds.Contains(uc.UserId))
                .GroupBy(uc => uc.UserId)
                .Select(uc => new { UserId = uc.Key, Count = uc.Count() })
                .ToListAsync();

            return userCommunities.ToDictionary(uc => uc.UserId, uc => uc.Count);
        }
    }

    /// <summary>
    /// 社区公告仓储实现
    /// </summary>
    public class CommunityAnnouncementRepository : Repository<CommunityAnnouncement>, ICommunityAnnouncementRepository
    {
        public CommunityAnnouncementRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityAnnouncement>> GetByCommunityIdAsync(Guid communityId)
        {
            return await _dbSet
                .Where(a => a.CommunityId == communityId)
                .OrderByDescending(a => a.CreatedAt)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityAnnouncement>> GetByUserIdAsync(Guid userId)
        {
            var communityIds = await _context.Set<UserCommunity>()
                .Where(uc => uc.UserId == userId)
                .Select(uc => uc.CommunityId)
                .ToListAsync();

            return await _dbSet
                .Where(a => communityIds.Contains(a.CommunityId))
                .OrderByDescending(a => a.CreatedAt)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityAnnouncement>> GetActiveAnnouncementsAsync(Guid communityId)
        {
            var now = DateTime.UtcNow;
            return await _dbSet
                .Where(a => a.CommunityId == communityId && a.IsActive && a.ExpiresAt > now)
                .OrderByDescending(a => a.CreatedAt)
                .ToListAsync();
        }

        public async Task<Dictionary<Guid, int>> GetAnnouncementCountByCommunitiesAsync(IEnumerable<Guid> communityIds)
        {
            var announcements = await _dbSet
                .Where(a => communityIds.Contains(a.CommunityId))
                .GroupBy(a => a.CommunityId)
                .Select(a => new { CommunityId = a.Key, Count = a.Count() })
                .ToListAsync();

            return announcements.ToDictionary(a => a.CommunityId, a => a.Count);
        }
    }

    /// <summary>
    /// 社区活动仓储实现
    /// </summary>
    public class CommunityActivityRepository : Repository<CommunityActivity>, ICommunityActivityRepository
    {
        public CommunityActivityRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityActivity>> GetByCommunityIdAsync(Guid communityId)
        {
            return await _dbSet
                .Where(a => a.CommunityId == communityId)
                .OrderBy(a => a.StartTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityActivity>> GetByUserIdAsync(Guid userId)
        {
            var communityIds = await _context.Set<UserCommunity>()
                .Where(uc => uc.UserId == userId)
                .Select(uc => uc.CommunityId)
                .ToListAsync();

            return await _dbSet
                .Where(a => communityIds.Contains(a.CommunityId))
                .OrderBy(a => a.StartTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityActivity>> GetUpcomingActivitiesAsync(Guid communityId)
        {
            var now = DateTime.UtcNow;
            return await _dbSet
                .Where(a => a.CommunityId == communityId && a.StartTime > now)
                .OrderBy(a => a.StartTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityActivity>> GetPastActivitiesAsync(Guid communityId)
        {
            var now = DateTime.UtcNow;
            return await _dbSet
                .Where(a => a.CommunityId == communityId && a.EndTime < now)
                .OrderByDescending(a => a.StartTime)
                .ToListAsync();
        }

        public async Task<Dictionary<Guid, int>> GetActivityCountByCommunitiesAsync(IEnumerable<Guid> communityIds)
        {
            var activities = await _dbSet
                .Where(a => communityIds.Contains(a.CommunityId))
                .GroupBy(a => a.CommunityId)
                .Select(a => new { CommunityId = a.Key, Count = a.Count() })
                .ToListAsync();

            return activities.ToDictionary(a => a.CommunityId, a => a.Count);
        }
    }

    /// <summary>
    /// 活动参与仓储实现
    /// </summary>
    public class ActivityParticipationRepository : Repository<ActivityParticipation>, IActivityParticipationRepository
    {
        public ActivityParticipationRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<ActivityParticipation>> GetByActivityIdAsync(Guid activityId)
        {
            return await _dbSet.Where(p => p.ActivityId == activityId).OrderBy(p => p.JoinedAt).ToListAsync();
        }

        public async Task<IEnumerable<ActivityParticipation>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(p => p.UserId == userId).OrderByDescending(p => p.JoinedAt).ToListAsync();
        }

        public async Task<ActivityParticipation?> GetByUserIdAndActivityIdAsync(Guid userId, Guid activityId)
        {
            return await _dbSet.FirstOrDefaultAsync(p => p.UserId == userId && p.ActivityId == activityId);
        }

        public async Task<bool> IsUserParticipatingAsync(Guid userId, Guid activityId)
        {
            return await _dbSet.AnyAsync(p => p.UserId == userId && p.ActivityId == activityId);
        }

        public async Task<Dictionary<Guid, int>> GetParticipantCountByActivitiesAsync(IEnumerable<Guid> activityIds)
        {
            var participations = await _dbSet
                .Where(p => activityIds.Contains(p.ActivityId))
                .GroupBy(p => p.ActivityId)
                .Select(p => new { ActivityId = p.Key, Count = p.Count() })
                .ToListAsync();

            return participations.ToDictionary(p => p.ActivityId, p => p.Count);
        }

        public async Task<Dictionary<Guid, int>> GetActivityCountByUsersAsync(IEnumerable<Guid> userIds)
        {
            var participations = await _dbSet
                .Where(p => userIds.Contains(p.UserId))
                .GroupBy(p => p.UserId)
                .Select(p => new { UserId = p.Key, Count = p.Count() })
                .ToListAsync();

            return participations.ToDictionary(p => p.UserId, p => p.Count);
        }
    }

    /// <summary>
    /// 用户关注仓储实现
    /// </summary>
    public class UserFollowRepository : Repository<UserFollow>, IUserFollowRepository
    {
        public UserFollowRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserFollow>> GetByFollowerIdAsync(Guid followerId)
        {
            return await _dbSet.Where(f => f.FollowerId == followerId).OrderByDescending(f => f.FollowedAt).ToListAsync();
        }

        public async Task<IEnumerable<UserFollow>> GetByFollowedIdAsync(Guid followedId)
        {
            return await _dbSet.Where(f => f.FollowedId == followedId).OrderByDescending(f => f.FollowedAt).ToListAsync();
        }

        public async Task<UserFollow?> GetByFollowerIdAndFollowedIdAsync(Guid followerId, Guid followedId)
        {
            return await _dbSet.FirstOrDefaultAsync(f => f.FollowerId == followerId && f.FollowedId == followedId);
        }

        public async Task<bool> IsUserFollowingAsync(Guid followerId, Guid followedId)
        {
            return await _dbSet.AnyAsync(f => f.FollowerId == followerId && f.FollowedId == followedId);
        }

        public async Task<Dictionary<Guid, int>> GetFollowerCountByUsersAsync(IEnumerable<Guid> userIds)
        {
            var follows = await _dbSet
                .Where(f => userIds.Contains(f.FollowedId))
                .GroupBy(f => f.FollowedId)
                .Select(f => new { UserId = f.Key, Count = f.Count() })
                .ToListAsync();

            return follows.ToDictionary(f => f.UserId, f => f.Count);
        }

        public async Task<Dictionary<Guid, int>> GetFollowingCountByUsersAsync(IEnumerable<Guid> userIds)
        {
            var follows = await _dbSet
                .Where(f => userIds.Contains(f.FollowerId))
                .GroupBy(f => f.FollowerId)
                .Select(f => new { UserId = f.Key, Count = f.Count() })
                .ToListAsync();

            return follows.ToDictionary(f => f.UserId, f => f.Count);
        }
    }

    /// <summary>
    /// 用户私信仓储实现
    /// </summary>
    public class UserMessageRepository : Repository<UserMessage>, IUserMessageRepository
    {
        public UserMessageRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserMessage>> GetBySenderIdAsync(Guid senderId)
        {
            return await _dbSet.Where(m => m.SenderId == senderId).OrderByDescending(m => m.SentAt).ToListAsync();
        }

        public async Task<IEnumerable<UserMessage>> GetByReceiverIdAsync(Guid receiverId)
        {
            return await _dbSet.Where(m => m.ReceiverId == receiverId).OrderByDescending(m => m.SentAt).ToListAsync();
        }

        public async Task<IEnumerable<UserMessage>> GetConversationAsync(Guid userId1, Guid userId2)
        {
            return await _dbSet
                .Where(m => (m.SenderId == userId1 && m.ReceiverId == userId2) || (m.SenderId == userId2 && m.ReceiverId == userId1))
                .OrderBy(m => m.SentAt)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserMessage>> GetUnreadMessagesAsync(Guid receiverId)
        {
            return await _dbSet
                .Where(m => m.ReceiverId == receiverId && !m.IsRead)
                .OrderBy(m => m.SentAt)
                .ToListAsync();
        }

        public async Task<int> GetUnreadMessageCountAsync(Guid receiverId)
        {
            return await _dbSet
                .CountAsync(m => m.ReceiverId == receiverId && !m.IsRead);
        }

        public async Task<Dictionary<Guid, int>> GetMessageCountByUsersAsync(IEnumerable<Guid> userIds)
        {
            var messages = await _dbSet
                .Where(m => userIds.Contains(m.SenderId) || userIds.Contains(m.ReceiverId))
                .ToListAsync();

            var result = new Dictionary<Guid, int>();
            foreach (var userId in userIds)
            {
                result[userId] = messages.Count(m => m.SenderId == userId || m.ReceiverId == userId);
            }

            return result;
        }

        public async Task MarkAsReadAsync(Guid messageId)
        {
            var message = await _dbSet.FindAsync(messageId);
            if (message != null && !message.IsRead)
            {
                message.IsRead = true;
                message.ReadAt = DateTime.UtcNow;
                await _context.SaveChangesAsync();
            }
        }

        public async Task MarkAllAsReadAsync(Guid receiverId, Guid senderId)
        {
            var messages = await _dbSet
                .Where(m => m.ReceiverId == receiverId && m.SenderId == senderId && !m.IsRead)
                .ToListAsync();

            foreach (var message in messages)
            {
                message.IsRead = true;
                message.ReadAt = DateTime.UtcNow;
            }

            await _context.SaveChangesAsync();
        }
    }
}